In [1]:
#------以下進行分析與評估資料------#
In [2]:
#---載入套件---#
import pandas as pd  #載入pandas套件,命名引用名稱pd
import numpy as np  #載入numpy套件,命名引用名稱np 
import matplotlib.pyplot as plt  #載入matplotlib.pyplot套件,命名引用名稱plt
import seaborn as sns  #載入seaborn套件,命名引用名稱sns
import plotly.express as px  #載入plotly.express套件,命名引用名稱px
In [3]:
#---讀取檔案---#
data = pd.read_csv(r'C:\Users\shen\Desktop\diabetes.csv')  #讀取csv檔,並把資料命名為'data'
data.head(10)  #顯示前10筆資料,確認有讀取成功
Out[3]:
Pregnancies Glucose BloodPressure SkinThickness Insulin BMI DiabetesPedigreeFunction Age Outcome
0 6 148 72 35 0 33.6 0.627 50 1
1 1 85 66 29 0 26.6 0.351 31 0
2 8 183 64 0 0 23.3 0.672 32 1
3 1 89 66 23 94 28.1 0.167 21 0
4 0 137 40 35 168 43.1 2.288 33 1
5 5 116 74 0 0 25.6 0.201 30 0
6 3 78 50 32 88 31.0 0.248 26 1
7 10 115 0 0 0 35.3 0.134 29 0
8 2 197 70 45 543 30.5 0.158 53 1
9 8 125 96 0 0 0.0 0.232 54 1
In [4]:
#---檢查數據類型---#
data.dtypes  #查看資料集內的特徵資料型態
Out[4]:
Pregnancies                   int64
Glucose                       int64
BloodPressure                 int64
SkinThickness                 int64
Insulin                       int64
BMI                         float64
DiabetesPedigreeFunction    float64
Age                           int64
Outcome                       int64
dtype: object
In [5]:
#---查看資料分布筆數---#
Count = data.groupby(["Pregnancies"], as_index=False)["Pregnancies"].agg({"cnt":"count"})
print(Count)  #顯示Pregnancies

Count = data.groupby(["Glucose"], as_index=False)["Glucose"].agg({"cnt":"count"})
print(Count)  #顯示Glucose

Count = data.groupby(["BloodPressure"], as_index=False)["BloodPressure"].agg({"cnt":"count"})
print(Count)  #顯示BloodPressure

Count = data.groupby(["SkinThickness"], as_index=False)["SkinThickness"].agg({"cnt":"count"})
print(Count)  #顯示SkinThickness

Count = data.groupby(["Insulin"], as_index=False)["Insulin"].agg({"cnt":"count"})
print(Count)  #顯示Insulin

Count = data.groupby(["BMI"], as_index=False)["BMI"].agg({"cnt":"count"})
print(Count)  #顯示BMI

Count = data.groupby(["DiabetesPedigreeFunction"], as_index=False)["DiabetesPedigreeFunction"].agg({"cnt":"count"})
print(Count)  #顯示DiabetesPedigreeFunction

Count = data.groupby(["Age"], as_index=False)["Age"].agg({"cnt":"count"})
print(Count)  #顯示Age

Count = data.groupby(["Outcome"], as_index=False)["Outcome"].agg({"cnt":"count"})
print(Count)  #顯示Outcome
    Pregnancies  cnt
0             0  111
1             1  135
2             2  103
3             3   75
4             4   68
5             5   57
6             6   50
7             7   45
8             8   38
9             9   28
10           10   24
11           11   11
12           12    9
13           13   10
14           14    2
15           15    1
16           17    1
     Glucose  cnt
0          0    5
1         44    1
2         56    1
3         57    2
4         61    1
..       ...  ...
131      195    2
132      196    3
133      197    4
134      198    1
135      199    1

[136 rows x 2 columns]
    BloodPressure  cnt
0               0   35
1              24    1
2              30    2
3              38    1
4              40    1
5              44    4
6              46    2
7              48    5
8              50   13
9              52   11
10             54   11
11             55    2
12             56   12
13             58   21
14             60   37
15             61    1
16             62   34
17             64   43
18             65    7
19             66   30
20             68   45
21             70   57
22             72   44
23             74   52
24             75    8
25             76   39
26             78   45
27             80   40
28             82   30
29             84   23
30             85    6
31             86   21
32             88   25
33             90   22
34             92    8
35             94    6
36             95    1
37             96    4
38             98    3
39            100    3
40            102    1
41            104    2
42            106    3
43            108    2
44            110    3
45            114    1
46            122    1
    SkinThickness  cnt
0               0  227
1               7    2
2               8    2
3              10    5
4              11    6
5              12    7
6              13   11
7              14    6
8              15   14
9              16    6
10             17   14
11             18   20
12             19   18
13             20   13
14             21   10
15             22   16
16             23   22
17             24   12
18             25   16
19             26   16
20             27   23
21             28   20
22             29   17
23             30   27
24             31   19
25             32   31
26             33   20
27             34    8
28             35   15
29             36   14
30             37   16
31             38    7
32             39   18
33             40   16
34             41   15
35             42   11
36             43    6
37             44    5
38             45    6
39             46    8
40             47    4
41             48    4
42             49    3
43             50    3
44             51    1
45             52    2
46             54    2
47             56    1
48             60    1
49             63    1
50             99    1
     Insulin  cnt
0          0  374
1         14    1
2         15    1
3         16    1
4         18    2
..       ...  ...
181      579    1
182      600    1
183      680    1
184      744    1
185      846    1

[186 rows x 2 columns]
      BMI  cnt
0     0.0   11
1    18.2    3
2    18.4    1
3    19.1    1
4    19.3    1
..    ...  ...
243  53.2    1
244  55.0    1
245  57.3    1
246  59.4    1
247  67.1    1

[248 rows x 2 columns]
     DiabetesPedigreeFunction  cnt
0                       0.078    1
1                       0.084    1
2                       0.085    2
3                       0.088    2
4                       0.089    1
..                        ...  ...
512                     1.893    1
513                     2.137    1
514                     2.288    1
515                     2.329    1
516                     2.420    1

[517 rows x 2 columns]
    Age  cnt
0    21   63
1    22   72
2    23   38
3    24   46
4    25   48
5    26   33
6    27   32
7    28   35
8    29   29
9    30   21
10   31   24
11   32   16
12   33   17
13   34   14
14   35   10
15   36   16
16   37   19
17   38   16
18   39   12
19   40   13
20   41   22
21   42   18
22   43   13
23   44    8
24   45   15
25   46   13
26   47    6
27   48    5
28   49    5
29   50    8
30   51    8
31   52    8
32   53    5
33   54    6
34   55    4
35   56    3
36   57    5
37   58    7
38   59    3
39   60    5
40   61    2
41   62    4
42   63    4
43   64    1
44   65    3
45   66    4
46   67    3
47   68    1
48   69    2
49   70    1
50   72    1
51   81    1
   Outcome  cnt
0        0  500
1        1  268
In [6]:
#---移除有缺值的欄位---#
columns_to_check = ['Glucose']  #檢查Glucose
data = data.drop(data.loc[(data[columns_to_check] == 0).all(axis=1)].index)  #上述項等於0表示資料有缺,故如果檢測出某列值等於0,則刪除該列,axis=1表示刪除

columns_to_check = ['BloodPressure']  #檢查BloodPressure
data = data.drop(data.loc[(data[columns_to_check] == 0).all(axis=1)].index)  #上述項等於0表示資料有缺,故如果檢測出某列值等於0,則刪除該列,axis=1表示刪除

columns_to_check = ['SkinThickness']  #檢查SkinThickness
data = data.drop(data.loc[(data[columns_to_check] == 0).all(axis=1)].index)  #上述項等於0表示資料有缺,故如果檢測出某列值等於0,則刪除該列,axis=1表示刪除

columns_to_check = ['Insulin']  #檢查Insulin
data = data.drop(data.loc[(data[columns_to_check] == 0).all(axis=1)].index)  #上述項等於0表示資料有缺,故如果檢測出某列值等於0,則刪除該列,axis=1表示刪除

columns_to_check = ['BMI']  #檢查BMI
data = data.drop(data.loc[(data[columns_to_check] == 0.0).all(axis=1)].index)  #上述項等於0.0表示資料有缺,故如果檢測出某列值等於0.0,則刪除該列,axis=1表示刪除

data = data.reset_index(drop=True)  #刪除列資料後,需要reset資料的索引index
In [7]:
#---檢查數值特徵分布---#
data.columns = [col for col in data.columns if data[col].dtype != 'object']  #檢查資料型態不是object的數量

plt.figure(figsize = (20,10))
plot_number = 1

for column in data.columns:
    if plot_number <= 14:
        ax = plt.subplot(3, 3, plot_number)
        sns.histplot(data[column])
        plt.xlabel(column)
    plot_number +=1
plt.tight_layout()
plt.show()
In [8]:
#---校正資料型態(把資料型態校正回正確的資料型態)---#
data.dtypes  #查看整份資料所有欄位資料型態
Out[8]:
Pregnancies                   int64
Glucose                       int64
BloodPressure                 int64
SkinThickness                 int64
Insulin                       int64
BMI                         float64
DiabetesPedigreeFunction    float64
Age                           int64
Outcome                       int64
dtype: object
In [9]:
data.Outcome.unique() #確認預測目標之資料型態為整數(int):1,0
Out[9]:
array([0, 1], dtype=int64)
In [10]:
data.head(10)  #顯示前10筆資料,確認有刪除成功
Out[10]:
Pregnancies Glucose BloodPressure SkinThickness Insulin BMI DiabetesPedigreeFunction Age Outcome
0 1 89 66 23 94 28.1 0.167 21 0
1 0 137 40 35 168 43.1 2.288 33 1
2 3 78 50 32 88 31.0 0.248 26 1
3 2 197 70 45 543 30.5 0.158 53 1
4 1 189 60 23 846 30.1 0.398 59 1
5 5 166 72 19 175 25.8 0.587 51 1
6 0 118 84 47 230 45.8 0.551 31 1
7 1 103 30 38 83 43.3 0.183 33 0
8 1 115 70 30 96 34.6 0.529 32 1
9 3 126 88 41 235 39.3 0.704 27 0
In [11]:
#---進行描述性統計,定義畫圖的公式---#
def violin(col):  #定義提琴圖,y軸為指定資料欄位,x軸為Outcome,color根據Outcome決定圖形顏色,template表示使用plotly內建的深色主題
    fig = px.violin(data, y=col, x="Outcome", color="Outcome", box=True, template = 'plotly_dark')
    return fig.show()

def kde(col):  #定義分布估計圖,hue參數根據Outcome的欄位進行繪製,height和aspect控制圖形大小和比例,使用map將sns.kdeplot應用到指定資料欄位,並用add_legend在旁附註曲線的分類
    grid = sns.FacetGrid(data, hue="Outcome", height = 6, aspect = 2)
    grid.map(sns.kdeplot, col)
    grid.add_legend()
    
def scatter(col1, col2):  #繪製散布圖,x軸為指定欄位col1,y軸為指定欄位col2,color根據Outcome決定圖形顏色,template表示使用plotly內建的深色主題
    fig = px.scatter(data, x= col1, y=col2, color="Outcome", template = 'plotly_dark')
    return fig.show()
In [12]:
violin('Glucose') 
In [13]:
violin('SkinThickness')
In [14]:
violin('Insulin')
In [15]:
violin('BMI')
In [16]:
violin('Age')
In [17]:
kde('Glucose')
In [18]:
kde('Insulin')
In [19]:
kde('Age')
In [20]:
scatter('Glucose', 'Insulin')
In [21]:
scatter('Glucose', 'DiabetesPedigreeFunction')
In [22]:
scatter('Glucose', 'BMI')
In [23]:
scatter('SkinThickness', 'BMI')
In [24]:
#根據提琴圖、分布估計圖、散布圖針對Glucose的分析可以發現,當Glucose數值低於120,沒有得糖尿病的人占多數。
#根據提琴圖、分布估計圖、散步圖針對Insulin的分析可以發現,當Insulin數值約90時,沒有患糖尿病的人占多數,而當Insulin數值開始高於160後,患有糖尿病的人就逐漸增加
#根據提琴圖、分布估計圖、散步圖針對Age的分析可以發現,年齡越大的人患有糖尿病的人越多
In [25]:
#---採用One-hot-encoding編碼方式,轉換成數值型態,使模型能夠使用可量化的資料---#
data_one_hot = pd.get_dummies(data)
data_one_hot.head(10)
Out[25]:
Pregnancies Glucose BloodPressure SkinThickness Insulin BMI DiabetesPedigreeFunction Age Outcome
0 1 89 66 23 94 28.1 0.167 21 0
1 0 137 40 35 168 43.1 2.288 33 1
2 3 78 50 32 88 31.0 0.248 26 1
3 2 197 70 45 543 30.5 0.158 53 1
4 1 189 60 23 846 30.1 0.398 59 1
5 5 166 72 19 175 25.8 0.587 51 1
6 0 118 84 47 230 45.8 0.551 31 1
7 1 103 30 38 83 43.3 0.183 33 0
8 1 115 70 30 96 34.6 0.529 32 1
9 3 126 88 41 235 39.3 0.704 27 0
In [26]:
#---區分特徵欄位和預測目標欄位---#
clear_data = data_one_hot.drop(['Outcome'],axis=1)  #用drop和axis=1將Outcome這個欄位移除,並將剩餘欄位命名為 clear_data(特徵欄位)
label = data_one_hot['Outcome']  #將Outcome欄位命名為 label(預測目標欄位),因為這是要預測的,所以不能放在特徵資料中
In [27]:
clear_data.head()  #顯示前5筆資料,確認有刪除成功
Out[27]:
Pregnancies Glucose BloodPressure SkinThickness Insulin BMI DiabetesPedigreeFunction Age
0 1 89 66 23 94 28.1 0.167 21
1 0 137 40 35 168 43.1 2.288 33
2 3 78 50 32 88 31.0 0.248 26
3 2 197 70 45 543 30.5 0.158 53
4 1 189 60 23 846 30.1 0.398 59
In [28]:
#-----以下進行模型開發-----#
In [29]:
# 將資料分成輸入特徵 (x_features) 和輸出標籤 (y_label)
x_features = data_one_hot.iloc[:,:-1] 
y_label = data_one_hot.iloc[:,-1] 
x_features 
Out[29]:
Pregnancies Glucose BloodPressure SkinThickness Insulin BMI DiabetesPedigreeFunction Age
0 1 89 66 23 94 28.1 0.167 21
1 0 137 40 35 168 43.1 2.288 33
2 3 78 50 32 88 31.0 0.248 26
3 2 197 70 45 543 30.5 0.158 53
4 1 189 60 23 846 30.1 0.398 59
... ... ... ... ... ... ... ... ...
387 0 181 88 44 510 43.3 0.222 26
388 1 128 88 39 110 36.5 1.057 37
389 2 88 58 26 16 28.4 0.766 22
390 10 101 76 48 180 32.9 0.171 63
391 5 121 72 23 112 26.2 0.245 30

392 rows × 8 columns

In [30]:
#---切分資料集---#
from sklearn.model_selection import KFold #導入KFold類別,將數據集劃分為k個子集,每個子集均做一次驗證,其餘k-1個子集則用於訓練
kf = KFold(n_splits=5, shuffle=True, random_state=27) #創建物件實例kf,n_splits指定將數據集分為5個子集,shuffle指定是否對數據集進行洗牌,減少數據集中的偏差,random_state指定隨機種子
In [31]:
#---選擇模型---#
#導入線性回歸模型
from sklearn.linear_model import LinearRegression 
model = LinearRegression() 
In [32]:
#---交叉驗證---#
#建立四個空的列表,用來記錄模型訓練和驗證的結果
test_bias = [] 
test_variance = []
train_errors = []
test_errors = []

#利用K-Fold交叉驗證來評估模型的表現
for train_index, test_index in kf.split(x_features):
    # 將資料分成訓練集和測試集
    X_train, y_train = x_features.iloc[train_index], y_label[train_index]
    X_test, y_test = x_features.iloc[test_index], y_label[test_index]
    
    #使用訓練數據來訓練模型
    model.fit(X_train, y_train) 
    
    #使用模型對訓練集和測試集進行預測
    y_train_pred = model.predict(X_train) 
    y_test_pred = model.predict(X_test)
    
    #計算測試集的偏差和方差
    bias = np.sum((y_test_pred - np.mean(y_test)) ** 2) / len(y_test_pred)
    variance = np.sum((y_test_pred - np.mean(y_test_pred)) ** 2) / len(y_test_pred)
    bias_2 = np.mean((y_test_pred - np.mean(y_test)) ** 2)
    variance_2 = np.var(y_test_pred)
    
    #將偏差和方差加入對應的列表中
    test_bias.append(bias)
    test_variance.append(variance)
    
    #計算訓練集和測試集的誤差並加入對應的列表中    
    train_error = np.sum((y_train_pred - y_train) ** 2) /len(y_train_pred)
    test_error = np.sum((y_test_pred - y_test) ** 2) / len(y_test_pred)
    train_errors.append(train_error) 
    test_errors.append(test_error)
In [33]:
#輸出偏差、方差、訓練誤差和測試誤差的平均值
print("Bias:",test_bias)
print("Variance:",test_variance)

print("平均訓練誤差:",sum(train_errors) / len(train_errors))
print("平均測試誤差:",sum(test_errors) / len(test_errors))
Bias: [0.06173376533192481, 0.07961531160219776, 0.07808017943498077, 0.08517315354396755, 0.09628003143551711]
Variance: [0.06039590930525523, 0.0773451895216898, 0.07613999536379225, 0.08273076794601372, 0.09605606082614357]
平均訓練誤差: 0.1443805607948426
平均測試誤差: 0.15072123674344412
In [ ]: